package dao

import (
	"fmt"
	"go-admin/config"
	"gorm.io/driver/mysql"
	"gorm.io/driver/postgres"
	"gorm.io/driver/sqlserver"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"log"
	"os"
	"time"
)

// Setup 初始化连接
func Setup(data config.Database) *gorm.DB {
	// db = newConnection()
	var dbURI string
	var dialector gorm.Dialector
	if data.Type == "mysql" {
		dbURI = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=true",
			data.User,
			data.Password,
			data.Host,
			data.Port,
			data.Name)
		dialector = mysql.New(mysql.Config{
			DSN:                       dbURI, // data source name
			DefaultStringSize:         256,   // default size for string fields
			DisableDatetimePrecision:  true,  // disable datetime precision, which not supported before MySQL 5.6
			DontSupportRenameIndex:    true,  // drop & create when rename index, rename index not supported before MySQL 5.7, MariaDB
			DontSupportRenameColumn:   true,  // `change` when rename column, rename column not supported before MySQL 8, MariaDB
			SkipInitializeWithVersion: false, // auto configure based on currently MySQL version
		})
	} else if data.Type == "postgres" {
		dbURI = fmt.Sprintf("host=%s port=%s user=%s dbname=%s sslmode=disable password=%s",
			data.Host,
			data.Port,
			data.User,
			data.Name,
			data.Password)
		dialector = postgres.New(postgres.Config{
			DSN:                  dbURI,
			PreferSimpleProtocol: true, // disables implicit prepared statement usage
		})

	} else if data.Type == "sqlserver" {
		dbURI = fmt.Sprintf("server=%s;port=%s;database=%s;user id=%s;password=%s;encrypt=disable",
			data.Host,
			data.Port,
			data.Name,
			data.User,
			data.Password,
		)
		dialector = sqlserver.New(sqlserver.Config{
			DSN: dbURI, // data source name
		})

	}

	newLogger := logger.New(
		log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer
		logger.Config{
			SlowThreshold:             time.Second,  // Slow SQL threshold
			LogLevel:                  logger.Error, // Log level
			IgnoreRecordNotFoundError: true,         // Ignore ErrRecordNotFound error for logger
			Colorful:                  false,        // Disable color
		},
	)

	conn, err := gorm.Open(dialector, &gorm.Config{
		Logger: newLogger,
	})
	if err != nil {
		log.Print(err.Error())
	}
	sqlDB, err := conn.DB()
	if err != nil {
		log.Printf("%s:%s connect db server failed.", data.Host, data.Port)
	}
	sqlDB.SetMaxIdleConns(6)                     // SetMaxIdleConns sets the maximum number of connections in the idle connection pool.
	sqlDB.SetMaxOpenConns(100)                   // SetMaxOpenConns sets the maximum number of open connections to the database.
	sqlDB.SetConnMaxLifetime(time.Second * 1000) // SetConnMaxLifetime sets the maximum amount of time a connection may be reused.
	data.Db = conn
	return conn
}

type DaoConfig struct {
	Dao    *gorm.DB
	Config config.Database
}

// GetDB 开放给外部获得db连接
func GetDB(config *DaoConfig) *gorm.DB {
	data := *config
	db := data.Dao
	sqlDB, err := db.DB()
	if err != nil {
		_ = fmt.Errorf("%s:%s connect db server failed", data.Config.Host, data.Config.Port)
		fmt.Println()
		db = Setup(data.Config)
	}
	if err := sqlDB.Ping(); err != nil {
		_ = sqlDB.Close()
		db = Setup(data.Config)
	}
	config.Dao = db
	return db
}
